package com.sunda.spmswms.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmswms.entity.SapBoxNote;
import com.sunda.spmswms.entity.SapBoxNoteDtl;
import com.sunda.spmswms.entity.WhsInventoryInfo;
import com.sunda.spmswms.entity.WhsStorageInventory;
import com.sunda.spmswms.mapper.SapRepackageMapper;
import com.sunda.spmswms.service.*;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

/**
 * @program: spms
 * @description:
 * @author: Wayne Wu
 * @create: 2021-10-21 11:10
 **/

@Slf4j
@Service
public class SapRepackageImpl implements ISapRepackage {

    @Autowired
    ISapBoxNoteService iSapBoxNoteService;

    @Autowired
    ISapBoxNoteDtlService iSapBoxNoteDtlService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsInventoryInfoService iWhsInventoryInfoService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    ISapDeliveryNoteLogService iSapDeliveryNoteLogService;

    @Autowired
    SapRepackageMapper sapRepackageMapper;

    /***
     {
     "boxNote": "BJ-10218800042-0305",
     "werks": "CN01",
     "whsLocationCode": "1061",
     "boxNoteDtl": [{
     "boxNote": "BJ-10218800042-0305",
     "item": 1,
     "domesticQtyReceived": 6
     }],
     "newBoxNoteDtl": [{
     "item": 1,
     "domesticQtyReceived": 2
     }]
     }
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult sapRepackageBox(JSONObject doc, String userId) {
        try {
            ResponseResult checkResult = checkData(doc);
            if (checkResult.getCode() != 200){
                return checkResult;
            }
            String boxNote = doc.getString("boxNote");
            String werks = doc.getString("werks");
            String whsLocationCode = doc.getString("whsLocationCode");
            JSONArray boxNoteDtl = doc.getJSONArray("boxNoteDtl");
            JSONArray newBoxNoteDtl = doc.getJSONArray("newBoxNoteDtl");
            String newBoxNote = generateBoxNote(whsLocationCode);

            SapBoxNote sapBoxNote = iSapBoxNoteService.getByBoxNote(boxNote);

            WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(boxNote);

            /** 拼接请求SAP，请求SAP */
            JSONObject dataToSap = repackageToSap(boxNote, boxNoteDtl, newBoxNote, newBoxNoteDtl);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("\n=====dataToSap======\n" + dataToSap + "\n=====sapReturnedMessage======\n" + message);

            if ("S".equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_TYPE"))){
                iSapDeliveryNoteLogService.insertSapRequestRecord(boxNote, userId,"拆箱成功，新箱码：" + newBoxNote, message.toJSONString(), dataToSap.toJSONString());
                iSapDeliveryNoteLogService.insertSapRequestRecord(newBoxNote, userId,"拆箱成功，原箱码：" + boxNote, message.toJSONString(), dataToSap.toJSONString());

                /** 1.修改原箱箱码表头信息 */
                //sapBoxNote.setRemarks(StringUtils.isEmpty(sapBoxNote.getRemarks()) ? "拆出新箱:" + newBoxNote : ";拆出新箱:" + newBoxNote);

                /** 2.修改原箱箱码明细信息 */
                for (int i = 0; i < boxNoteDtl.size(); i++){
                    int item = boxNoteDtl.getJSONObject(i).getInteger("item");
                    double domesticQtyReceived = boxNoteDtl.getJSONObject(i).getDoubleValue("domesticQtyReceived");
                    iSapBoxNoteDtlService.updateSapBoxNoteDtlBeta(boxNote, item, domesticQtyReceived, newBoxNote);
                }

                /** 3.新增新箱码表头信息 */
                sapBoxNote.setBoxNote(newBoxNote);
                sapBoxNote.setParentBoxNote(boxNote);
                iSapBoxNoteService.save(sapBoxNote);

                /** 4.新增新箱码明细信息 */
                for (int j = 0; j < newBoxNoteDtl.size(); j++){
                    int item = newBoxNoteDtl.getJSONObject(j).getInteger("item");
                    double domesticQtyReceived = newBoxNoteDtl.getJSONObject(j).getDoubleValue("domesticQtyReceived");
                    QueryWrapper<SapBoxNoteDtl> queryWrapper = new QueryWrapper<SapBoxNoteDtl>().eq("BOX_NOTE", boxNote).eq("ITEM", item);
                    SapBoxNoteDtl sapBoxNoteDtl = iSapBoxNoteDtlService.getOne(queryWrapper);
                    sapBoxNoteDtl.setBoxNote(newBoxNote);
                    /** 拆出的新箱码明细，数量(应收数量) QUANTITY、国内收数量 DOMESTIC_QTY_RECEIVABLE 字段值都给 0 ————20211026 */
                    sapBoxNoteDtl.setQuantity(0.0);
                    sapBoxNoteDtl.setDomesticQtyReceivable(0.0);
                    sapBoxNoteDtl.setDomesticQtyReceived(domesticQtyReceived);
                    iSapBoxNoteDtlService.save(sapBoxNoteDtl);
                }

                /** 5.新增储位库存、记录储位库存增加日志 */
                String uuidStorage = whsStorageInventory.getUuid();
                iWhsStorageInventoryService.updateStorageInvX(uuidStorage, newBoxNote, 1, "add");
                iWhsOperateLogService.insertWhsOperateLog("2", uuidStorage, "", newBoxNote, 1, "2", newBoxNote,
                        "拆箱增加储位库存", userId, "拆箱增加储位库存", werks, whsLocationCode);


                /** 6.新增仓库库存、记录仓库库存增加日志 */
                iWhsInventoryInfoService.updateWhsInventoryX(werks, whsLocationCode, newBoxNote, 1, "add", userId);
                iWhsOperateLogService.insertWhsOperateLog("1", "", "", newBoxNote, 1, "1", newBoxNote,
                        "拆箱增加仓库库存", userId, "拆箱增加仓库库存", werks, whsLocationCode);

                return ResponseResult.success()
                        .add("newBoxNote", iSapBoxNoteService.getByBoxNote(newBoxNote))
                        .add("newBoxNoteDtl", iSapBoxNoteDtlService.getSapBoxNoteDtlList(newBoxNote))
                        .add("boxNoteDtl", iSapBoxNoteDtlService.getSapBoxNoteDtlList(boxNote))
                        .add("dataToSap", dataToSap)
                        .add("sapReturnedMessage", message);
            } else {
                iSapDeliveryNoteLogService.insertSapRequestRecord(boxNote, userId,"拆箱失败", message.toJSONString(), dataToSap.toJSONString());
                return ResponseResult.error()
                        .add("dataToSap", dataToSap)
                        .add("sapReturnedMessage", message);
            }
        }catch (FeignException feignException){
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    /**
     {
     "boxNote": "BJ-10218800042-0305",
     "werks": "CN01",
     "whsLocationCode": "1061",
     "boxNoteDtl": [{
     "boxNote": "BJ-10218800042-0305",
     "item": 1,
     "domesticQtyReceived": 6
     }],
     "newBoxNoteDtl": [{
     "item": 1,
     "domesticQtyReceived": 2
     }]
     }
     * @param doc
     * @return
     */
    ResponseResult checkData(JSONObject doc){
        if (!doc.containsKey("boxNote") || !doc.containsKey("boxNoteDtl") || !doc.containsKey("newBoxNoteDtl")){
            return ResponseResult.error("请求参数错误请重试");
        }
        String boxNote = doc.getString("boxNote");
        String werks = doc.getString("werks");
        String whsLocationCode = doc.getString("whsLocationCode");
        JSONArray boxNoteDtl = doc.getJSONArray("boxNoteDtl");
        JSONArray newBoxNoteDtl = doc.getJSONArray("newBoxNoteDtl");

        if (StringUtils.isEmpty(boxNote) || StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode)
                || boxNoteDtl.size() == 0 || newBoxNoteDtl.size() == 0 || boxNoteDtl.size() != newBoxNoteDtl.size()){
            return ResponseResult.error("请求参数错误请重试");
        }
        WhsInventoryInfo whsInventoryInfo = iWhsInventoryInfoService.getWhsInventoryInfoByBoxNote(boxNote, werks, whsLocationCode);
        if (whsInventoryInfo == null){
            return ResponseResult.error("请求箱码仓库库存不存在，操作终止");
        }
        WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(boxNote);
        if (whsStorageInventory == null){
            return ResponseResult.error("请求箱码储位库存不存在，操作终止");
        }
        for (int i = 0; i < boxNoteDtl.size(); i ++){
            JSONObject obj = boxNoteDtl.getJSONObject(i);
            String item = obj.getString("item");
            List<SapBoxNoteDtl> boxNoteDtlList = iSapBoxNoteDtlService.getBoxNoteDtlList(boxNote, item);
            if (boxNoteDtlList == null){
                return ResponseResult.error("请求箱码明细数据不存在");
            }
            if (boxNoteDtlList.size() > 1){
                return ResponseResult.error("请求箱码明细数据不正确");
            }
        }
        return ResponseResult.success();
    }

    JSONObject repackageToSap(String boxNote, JSONArray boxNoteDtl, String newBoxNote, JSONArray newBoxNoteDtl){
        JSONObject doc = new JSONObject();
        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        Map<String, Object> Head = sapRepackageMapper.getHeadToSap(boxNote);
        JSONObject MapItems = new JSONObject();
        JSONArray IT_XHEAD = formatItXHead(boxNote, newBoxNote);
        List<Map<String, Object>> IT_ITME = formatItItem(boxNote, boxNoteDtl, newBoxNote, newBoxNoteDtl);

        MapItems.put("IT_ITME", IT_ITME);
        MapItems.put("IT_XHEAD", IT_XHEAD);

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("MapItems", MapItems);
        REQUEST_DATA.put("Operation", "Z_SPMS_SETBOXCODE");
        REQUEST_DATA.put("Type", "SETBOXCODE");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);

        doc.put("REQUEST", REQUEST);
        return doc;
    }

    /** 转换箱码信息传输SAP结构 */
    JSONArray formatItXHead(String boxNote, String newBoxNote){
        JSONArray array = new JSONArray();
        Map<String, Object> boxNoteToSap = sapRepackageMapper.boxNoteToSap(boxNote);
        Map<String, Object> newBoxNoteToSap = new HashMap<>();
        array.add(boxNoteToSap);
        boxNoteToSap.forEach((key, value) -> {
            if ("packageCode".equals(key)){
                newBoxNoteToSap.put(key, newBoxNote);
            } else {
                newBoxNoteToSap.put(key, value);
            }
        });
        array.add(newBoxNoteToSap);
        return array;
    }

    /** 转换箱码明细信息传输SAP结构 */
    List<Map<String, Object>> formatItItem(String boxNote, JSONArray boxNoteDtl, String newBoxNote, JSONArray newBoxNoteDtl){
        List<Map<String, Object>> mapList = new ArrayList<>();
        List<SapBoxNoteDtl> sapBoxNoteDtlList = iSapBoxNoteDtlService.getSapBoxNoteDtlList(boxNote);
        List<SapBoxNoteDtl> dataToSap = new ArrayList<>();
        for (SapBoxNoteDtl sapBoxNoteDtl : sapBoxNoteDtlList){
            String item = sapBoxNoteDtl.getItem().toString();
            for (int i = 0; i < boxNoteDtl.size(); i ++){
                JSONObject doc = boxNoteDtl.getJSONObject(i);
                double domesticQtyReceived = doc.getDoubleValue("domesticQtyReceived");
                if (item.equals(doc.getString("item"))){
                    sapBoxNoteDtl.setDomesticQtyReceived(domesticQtyReceived);
                }
            }
            /** 原箱更新后的信息结构加到请求SAP中 */
            dataToSap.add(sapBoxNoteDtl);
        }

        for (SapBoxNoteDtl sapBoxNoteDtl : sapBoxNoteDtlList){
            String item = sapBoxNoteDtl.getItem().toString();
            for (int j = 0; j < newBoxNoteDtl.size(); j ++){
                SapBoxNoteDtl dtl = new SapBoxNoteDtl();
                JSONObject obj = newBoxNoteDtl.getJSONObject(j);
                double domesticQtyReceived = obj.getDoubleValue("domesticQtyReceived");
                if (item.equals(obj.getString("item"))){
                    dtl.setBoxNote(newBoxNote);
                    dtl.setDomesticQtyReceivable(domesticQtyReceived);
                    dtl.setDomesticQtyReceived(domesticQtyReceived);
                    dtl.setPackageNote(sapBoxNoteDtl.getPackageNote());
                    dtl.setItem(sapBoxNoteDtl.getItem());
                    dtl.setPackagePosnr(sapBoxNoteDtl.getPackagePosnr());
                    dtl.setMaterialNo(sapBoxNoteDtl.getMaterialNo());
                    dtl.setSpecs(sapBoxNoteDtl.getSpecs());
                    dtl.setQuantity(sapBoxNoteDtl.getQuantity());
                    dtl.setBasicUnit(sapBoxNoteDtl.getBasicUnit());
                    dtl.setSrmContractNo(sapBoxNoteDtl.getSrmContractNo());
                    dtl.setPurchaseNo(sapBoxNoteDtl.getPurchaseNo());
                    dtl.setPurchaseNoItem(sapBoxNoteDtl.getPurchaseNoItem());
                    dtl.setDeliveryNoteSap(sapBoxNoteDtl.getDeliveryNoteSap());
                    dtl.setDeliveryNoteSapItem(sapBoxNoteDtl.getDeliveryNoteSapItem());
                    dtl.setDemandNo(sapBoxNoteDtl.getDemandNo());
                    dtl.setDemandNoItem(sapBoxNoteDtl.getDemandNoItem());
                    dtl.setDemander(sapBoxNoteDtl.getDemander());
                    dtl.setRemark(sapBoxNoteDtl.getRemark());
                    dtl.setGrossWeight(sapBoxNoteDtl.getGrossWeight());
                    dtl.setNetWeight(sapBoxNoteDtl.getNetWeight());
                    dtl.setOverseaQtyReceived(0.0);

                    /** 生成的新箱码信息结构加到请求SAP中 */
                    dataToSap.add(dtl);
                }
            }
        }

        for (SapBoxNoteDtl sapBoxNoteDtl: dataToSap){
            Map<String, Object> map = new HashMap<>();
            map.put("packageNo", sapBoxNoteDtl.getPackageNote());
            map.put("serial", sapBoxNoteDtl.getItem().toString());
            map.put("packageCode", sapBoxNoteDtl.getBoxNote());
            map.put("packagePosnr", sapBoxNoteDtl.getPackagePosnr() != null ? sapBoxNoteDtl.getPackagePosnr().toString() : "");
            map.put("matnr", sapBoxNoteDtl.getMaterialNo());
            map.put("specs", sapBoxNoteDtl.getSpecs() != null ? sapBoxNoteDtl.getSpecs() : "");
            map.put("menge", sapBoxNoteDtl.getQuantity() != null ? sapBoxNoteDtl.getQuantity().toString() : "0");
            map.put("meins", sapBoxNoteDtl.getBasicUnit());
            map.put("srmContractNo", sapBoxNoteDtl.getSrmContractNo() != null ? sapBoxNoteDtl.getSrmContractNo() : "");
            map.put("ebeln", sapBoxNoteDtl.getPurchaseNo() != null ? sapBoxNoteDtl.getPurchaseNo() : "");
            map.put("ebelp", sapBoxNoteDtl.getPurchaseNoItem() != null ? sapBoxNoteDtl.getPurchaseNoItem().toString() : "");
            map.put("vbeln", sapBoxNoteDtl.getDeliveryNoteSap() != null ? sapBoxNoteDtl.getDeliveryNoteSap() : "");
            map.put("posnr", sapBoxNoteDtl.getDeliveryNoteSapItem() != null ? sapBoxNoteDtl.getDeliveryNoteSapItem().toString() : "");
            map.put("demandNo", sapBoxNoteDtl.getDemandNo() != null ? sapBoxNoteDtl.getDemandNo() : "");
            map.put("demandPosnr", sapBoxNoteDtl.getDemandNoItem() != null ? sapBoxNoteDtl.getDemandNoItem().toString() : "");
            map.put("demander", sapBoxNoteDtl.getDemander() != null ? sapBoxNoteDtl.getDemander() : "");
            map.put("mark", sapBoxNoteDtl.getRemark() != null ? sapBoxNoteDtl.getRemark() : "");
            map.put("brgew", sapBoxNoteDtl.getGrossWeight() != null ? sapBoxNoteDtl.getGrossWeight().toString() : "0");
            map.put("ntgew", sapBoxNoteDtl.getNetWeight() != null ? sapBoxNoteDtl.getNetWeight().toString() : "0");
            map.put("gnshsl", sapBoxNoteDtl.getDomesticQtyReceivable() != null ? sapBoxNoteDtl.getDomesticQtyReceivable().toString() : "0");
            map.put("gnsjsl", sapBoxNoteDtl.getDomesticQtyReceived() != null ? sapBoxNoteDtl.getDomesticQtyReceived().toString() : "0");
            map.put("hwshsl", sapBoxNoteDtl.getOverseaQtyReceived() != null ? sapBoxNoteDtl.getOverseaQtyReceived().toString() : "0");
            mapList.add(map);
        }
        return mapList;
    }

    /** 生成新箱码 CX-10611000001-0101 */
    String generateBoxNote(String whsLocationCode){
        int getNewBoxNote = iSapBoxNoteService.getNewBoxNote();
        return "CX-" + whsLocationCode + getNewBoxNote + "-0101";
    }

    @Override
    public ResponseResult getSapBoxNoteListPage(String werks, String whsLocationCode, String boxNote, Integer pageNo, Integer pageSize) {
        ResponseResult checkResult = checkValidate(werks, whsLocationCode, pageNo, pageSize);
        if (checkResult.getCode() != 200){
            return checkResult;
        }
        pageNo = pageNo <= 0 ? 1 : pageNo;
        pageSize = pageSize <= 0 ? 20 : pageSize;
        boxNote = StringUtils.isEmpty(boxNote) ? null : boxNote;
        Page<Map<String, Object>> mapPage = new Page<>(pageNo, pageSize);
        List<Map<String, Object>> pageMaData = sapRepackageMapper.pageMaDataMap(mapPage, werks, whsLocationCode, boxNote);
        mapPage.setRecords(pageMaData);
        return ResponseResult.success().add("sapBoxNoteList", mapPage);
    }

    ResponseResult checkValidate(String werks, String whsLocationCode, Integer pageNo, Integer pageSize){
        if (StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode)){
            return ResponseResult.error("请求参数错误");
        }
        return ResponseResult.success();
    }
}


